API 认证
在返回响应之前,大多数 API
需要通过某种形式的身份验证。 有时,经过和未经过身份验证的请求,响应的内容会有所不同。
这个软件包允许您配置多个身份验证提供者。 当启用身份验证后,每一个提供者都会尝试对请求进行身份验证。
配置身份验证提供者
默认情况下,仅在配置文件中启用 HTTP
基本身份验证。以下是该包内置支持身份验证提供者的列表:
- HTTP Basic (
Dingo\Api\Auth\Provider\Basic
) - JSON Web Tokens (
Dingo\Api\Auth\Provider\JWT
) - OAuth 2.0 (
Dingo\Api\Auth\Provider\OAuth2
)
HTTP 基本验证
这个服务提供者使用 laravel
和 lumen
中内置的默认基本身份验证。 您需要在配置文件或者引导文件中配置此服务提供者,第二个参数用于认证的标识符。
app('Dingo\Api\Auth\Auth')->extend('basic', function ($app) {
return new Dingo\Api\Auth\Provider\Basic($app['auth'], 'email');
});
JSON Web Tokens (JWT)
tymon/jwt-auth
是使用第三方来集成 JWT
身份验证的软件包。 有关安装和配置的详细信息,请参阅 GitHub
页面。
一旦您安装了这个软件包,您就可以在 config/api.php
文件或者引导文件中配置该服务提供者。
'auth' => [
'jwt' => 'Dingo\Api\Auth\Provider\JWT',
],
app('Dingo\Api\Auth\Auth')->extend('jwt', function ($app) {
return new Dingo\Api\Auth\Provider\JWT($app['Tymon\JWTAuth\JWTAuth']);
});
OAuth 2.0
这个包是使用第三方来集成的 OAuth 2.0
。 您可以安装 league/oauth2-server
并配置服务提供者,或者,您也可以使用 lucadegasperi/oauth2-server-laravel
。
为了简单起见,以下例子将使用
lucadegasperi/oauth2-server-laravel
这个 Laravel 定制包。
一旦您安装了这个包,您需要配置 provider
或者 bootstrap
文件。
app('Dingo\Api\Auth\Auth')->extend('oauth', function ($app) {
$provider = new Dingo\Api\Auth\Provider\OAuth2($app['oauth2-server.authorizer']->getChecker());
$provider->setUserResolver(function ($id) {
// 获取用户 ID 的代码逻辑
});
$provider->setClientResolver(function ($id) {
// 通过 Client ID 获取 OAuth Client 的逻辑
});
return $provider;
});
或者配置服务提供者。
namespace App\Providers;
use Dingo\Api\Auth\Auth;
use Dingo\Api\Auth\Provider\OAuth2;
use Illuminate\Support\ServiceProvider;
class OAuthServiceProvider extends ServiceProvider
{
public function boot()
{
$this->app[Auth::class]->extend('oauth', function ($app) {
$provider = new OAuth2($app['oauth2-server.authorizer']->getChecker());
$provider->setUserResolver(function ($id) {
// 获取用户 ID 的代码逻辑
});
$provider->setClientResolver(function ($id) {
// 通过 Client ID 获取 OAuth Client 的逻辑
});
return $provider;
});
}
public function register()
{
//
}
}
用户和客户端解析器
根据授权许可,您可能不需要2个解析器。例如:如果您只需要客户端通过 OAuth 2.0
身份验证,则不需要配置用户解析器。
解析器都接收用户或者客户端的 ID,并用这个 ID 返回用户或者客户端的实例。这通常涉及用户或者客户端的数据库查询。
自定义身份验证
如果您正在维护以前的系统或者需要其他形式的身份验证,则可以实施自定义身份验证。
您的身份验证提供者应该实现 Dingo\Api\Contract\Auth\Provider
。如果通过身份验证,身份验证提供者应该返回该用户的实例, 如果身份验证失败,则抛出一个 Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException
异常
use Illuminate\Http\Request;
use Dingo\Api\Routing\Route;
use Dingo\Api\Contract\Auth\Provider;
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
class CustomProvider implements Provider
{
public function authenticate(Request $request, Route $route)
{
// 对请求进行验证的逻辑
throw new UnauthorizedHttpException('Unable to authenticate with supplied username and password.');
}
}
Dingo\Api\Auth\Provider\Authorization
将颁发一个带 Authorization
头信息的 token
。 Dingo\Api\Auth\Provider\Authorization::validateAuthorizationHeader
可以轻松的验证 Authorization
头信息是否存在,并且是有效的。
use Illuminate\Http\Request;
use Dingo\Api\Routing\Route;
use Dingo\Api\Auth\Provider\Authorization;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
class CustomProvider extends Authorization
{
public function authenticate(Request $request, Route $route)
{
$this->validateAuthorizationHeader($request);
// 如果 Authorization 通过验证,我们可以继续进行身份验证
// 如果 Authorization 验证失败, 我们必须抛出一个 UnauthorizedHttpException 的异常。
}
public function getAuthorizationMethod()
{
return 'mac';
}
}
一旦您实现了自己的身份验证提供者,您需要在 config/api.php
这个文件进行配置。
'auth' => [
'custom' => 'CustomProvider',
],
或者,配置 bootstrap
或 provider
文件。
app('Dingo\Api\Auth\Auth')->extend('custom', function ($app) {
return new CustomProvider;
});
保护级别
您可以通过 api.auth
路由中间件来启用路由或者路由群组的保护。
如果您使用
Laravel
的定制包。则可以直接使用api.auth
这个中间件。并且不需要注册。
在所有的路由上启用
$api->version('v1', ['middleware' => 'api.auth'], function ($api) {
// 在这个版本群组下的所有路由将进行身份验证。
});
特定的路由上启用
$api->version('v1', function ($api) {
$api->get('user', ['middleware' => 'api.auth', function () {
// 这个路由将进行身份验证。
}]);
$api->get('posts', function () {
// 这个路由不会验证身份。
});
});
只允许特定的身份验证提供者
如果你想在一个群组或者特定的路由上验证身份验证提供者。你可以启用 providers
来配置。
$api->version('v1', function ($api) {
$api->get('user', ['middleware' => 'api.auth', 'providers' => ['basic', 'oauth'], function () {
// 这个路由将进行身份验证。
}]);
});
控制器上进行身份验证
Laravel
和 Lumen
都可以在控制器里启用中间件。您可以在构造函数里使用 middleware
的方法。
class UserController extends Illuminate\Routing\Controller
{
use Helpers;
public function __construct()
{
$this->middleware('api.auth');
// 这个中间件只在 index 中启用
$this->middleware('api.auth', ['only' => ['index']]);
}
public function index()
{
//
}
public function posts()
{
//
}
}
检索经过身份验证的用户
你可以在受保护的接口里检索已通过身份验证的用户
$api->version('v1', ['middleware' => 'api.auth'], function ($api) {
$api->get('user', function () {
$user = app('Dingo\Api\Auth\Auth')->user();
return $user;
});
});
如果你的控制器里使用了 Dingo\Api\Routing\Helpers
那么你就可以使用 $auth
。
use Dingo\Api\Routing\Helpers;
use Illuminate\Routing\Controller;
class UserController extends Controller
{
use Helpers;
public function __construct()
{
$this->middleware('api.auth');
}
public function index()
{
$user = $this->auth->user();
return $user;
}
}
可选的验证
有时你可能需要根据请求是否通过身份验证来修改响应值,为此,路由不应该设置中间件去保护,你只需要手动认证用户。
$api->version('v1', function ($api) {
$api->get('users/{id}', function ($id) {
$user = User::findOrFail($id);
// 尝试验证请求。如果请求未被认证那么我们会从响应中隐藏电子邮件。只认证
// 请求可以看到其他用户的电子邮件。
if (! app('Dingo\Api\Auth\Auth')->user()) {
$hidden = $user->getHidden();
$user->setHidden(array_merge($hidden, ['email']));
}
return $user;
});
});